diff --git a/deploy/crds/crd-certificates.yaml b/deploy/crds/crd-certificates.yaml
index ec7d01b48..62a3abbce 100644
--- a/deploy/crds/crd-certificates.yaml
+++ b/deploy/crds/crd-certificates.yaml
@@ -80,6 +80,9 @@ spec:
                         enum:
                           - DER
                           - CombinedPEM
+                certificateOwnerRef:
+                  description: CertificateOwnerRef is whether to set the certificate resource as an owner of secret where the tls certificate is stored. When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted. If unset (`nil`) `--enable-certificate-owner-ref` CLI parameter value is used. Default value is `nil`.
+                  type: boolean
                 commonName:
                   description: 'CommonName is a common name to be used on the Certificate. The CommonName should have a length of 64 characters or fewer to avoid generating invalid CSRs. This value is ignored by TLS clients when any subject alt name is set. This is x509 behaviour: https://tools.ietf.org/html/rfc6125#section-6.4.4'
                   type: string
diff --git a/internal/apis/certmanager/types_certificate.go b/internal/apis/certmanager/types_certificate.go
index 6163a19a9..a610384b6 100644
--- a/internal/apis/certmanager/types_certificate.go
+++ b/internal/apis/certmanager/types_certificate.go
@@ -178,6 +178,11 @@ type CertificateSpec struct {
 	// `--feature-gates=AdditionalCertificateOutputFormats=true` option on both
 	// the controller and webhook components.
 	AdditionalOutputFormats []CertificateAdditionalOutputFormat
+
+	// CertificateOwnerRef is whether to set the certificate resource as an owner of secret where the tls certificate is stored.
+	// When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted.
+	// If unset (`nil`) `--enable-certificate-owner-ref` CLI parameter value is used. Default value is `nil`.
+	CertificateOwnerRef *bool
 }
 
 // CertificatePrivateKey contains configuration options for private keys
diff --git a/internal/apis/certmanager/v1/zz_generated.conversion.go b/internal/apis/certmanager/v1/zz_generated.conversion.go
index 41e6cd26b..e8ec0dcd1 100644
--- a/internal/apis/certmanager/v1/zz_generated.conversion.go
+++ b/internal/apis/certmanager/v1/zz_generated.conversion.go
@@ -845,6 +845,7 @@ func autoConvert_v1_CertificateSpec_To_certmanager_CertificateSpec(in *v1.Certif
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]certmanager.CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
@@ -878,6 +879,7 @@ func autoConvert_certmanager_CertificateSpec_To_v1_CertificateSpec(in *certmanag
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]v1.CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
diff --git a/internal/apis/certmanager/v1alpha2/types_certificate.go b/internal/apis/certmanager/v1alpha2/types_certificate.go
index 5872612d7..69706178b 100644
--- a/internal/apis/certmanager/v1alpha2/types_certificate.go
+++ b/internal/apis/certmanager/v1alpha2/types_certificate.go
@@ -223,6 +223,11 @@ type CertificateSpec struct {
 	// the controller and webhook components.
 	// +optional
 	AdditionalOutputFormats []CertificateAdditionalOutputFormat `json:"additionalOutputFormats,omitempty"`
+
+	// CertificateOwnerRef is whether to set the certificate resource as an owner of secret where the tls certificate is stored.
+	// When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted.
+	// If unset (`nil`) `--enable-certificate-owner-ref` CLI parameter value is used. Default value is `nil`.
+	CertificateOwnerRef *bool
 }
 
 // CertificatePrivateKey contains configuration options for private keys
diff --git a/internal/apis/certmanager/v1alpha2/zz_generated.conversion.go b/internal/apis/certmanager/v1alpha2/zz_generated.conversion.go
index 427b8c168..615809611 100644
--- a/internal/apis/certmanager/v1alpha2/zz_generated.conversion.go
+++ b/internal/apis/certmanager/v1alpha2/zz_generated.conversion.go
@@ -845,6 +845,7 @@ func autoConvert_v1alpha2_CertificateSpec_To_certmanager_CertificateSpec(in *Cer
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]certmanager.CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
@@ -894,6 +895,7 @@ func autoConvert_certmanager_CertificateSpec_To_v1alpha2_CertificateSpec(in *cer
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
diff --git a/internal/apis/certmanager/v1alpha2/zz_generated.deepcopy.go b/internal/apis/certmanager/v1alpha2/zz_generated.deepcopy.go
index fba61454a..029902566 100644
--- a/internal/apis/certmanager/v1alpha2/zz_generated.deepcopy.go
+++ b/internal/apis/certmanager/v1alpha2/zz_generated.deepcopy.go
@@ -472,6 +472,11 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
 		*out = make([]CertificateAdditionalOutputFormat, len(*in))
 		copy(*out, *in)
 	}
+	if in.CertificateOwnerRef != nil {
+		in, out := &in.CertificateOwnerRef, &out.CertificateOwnerRef
+		*out = new(bool)
+		**out = **in
+	}
 	return
 }
 
diff --git a/internal/apis/certmanager/v1alpha3/types_certificate.go b/internal/apis/certmanager/v1alpha3/types_certificate.go
index 7748fdad0..bce015b4f 100644
--- a/internal/apis/certmanager/v1alpha3/types_certificate.go
+++ b/internal/apis/certmanager/v1alpha3/types_certificate.go
@@ -221,6 +221,11 @@ type CertificateSpec struct {
 	// the controller and webhook components.
 	// +optional
 	AdditionalOutputFormats []CertificateAdditionalOutputFormat `json:"additionalOutputFormats,omitempty"`
+
+	// CertificateOwnerRef is whether to set the certificate resource as an owner of secret where the tls certificate is stored.
+	// When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted.
+	// If unset (`nil`) `--enable-certificate-owner-ref` CLI parameter value is used. Default value is `nil`.
+	CertificateOwnerRef *bool
 }
 
 // CertificatePrivateKey contains configuration options for private keys
diff --git a/internal/apis/certmanager/v1alpha3/zz_generated.conversion.go b/internal/apis/certmanager/v1alpha3/zz_generated.conversion.go
index 958d721f4..d93893dc5 100644
--- a/internal/apis/certmanager/v1alpha3/zz_generated.conversion.go
+++ b/internal/apis/certmanager/v1alpha3/zz_generated.conversion.go
@@ -844,6 +844,7 @@ func autoConvert_v1alpha3_CertificateSpec_To_certmanager_CertificateSpec(in *Cer
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]certmanager.CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
@@ -893,6 +894,7 @@ func autoConvert_certmanager_CertificateSpec_To_v1alpha3_CertificateSpec(in *cer
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
diff --git a/internal/apis/certmanager/v1alpha3/zz_generated.deepcopy.go b/internal/apis/certmanager/v1alpha3/zz_generated.deepcopy.go
index 6f3bcaebc..8fdd3edd4 100644
--- a/internal/apis/certmanager/v1alpha3/zz_generated.deepcopy.go
+++ b/internal/apis/certmanager/v1alpha3/zz_generated.deepcopy.go
@@ -467,6 +467,11 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
 		*out = make([]CertificateAdditionalOutputFormat, len(*in))
 		copy(*out, *in)
 	}
+	if in.CertificateOwnerRef != nil {
+		in, out := &in.CertificateOwnerRef, &out.CertificateOwnerRef
+		*out = new(bool)
+		**out = **in
+	}
 	return
 }
 
diff --git a/internal/apis/certmanager/v1beta1/types_certificate.go b/internal/apis/certmanager/v1beta1/types_certificate.go
index 2f2a5b18f..057baf771 100644
--- a/internal/apis/certmanager/v1beta1/types_certificate.go
+++ b/internal/apis/certmanager/v1beta1/types_certificate.go
@@ -198,6 +198,11 @@ type CertificateSpec struct {
 	// the controller and webhook components.
 	// +optional
 	AdditionalOutputFormats []CertificateAdditionalOutputFormat `json:"additionalOutputFormats,omitempty"`
+
+	// CertificateOwnerRef is whether to set the certificate resource as an owner of secret where the tls certificate is stored.
+	// When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted.
+	// If unset (`nil`) `--enable-certificate-owner-ref` CLI parameter value is used. Default value is `nil`.
+	CertificateOwnerRef *bool
 }
 
 // CertificatePrivateKey contains configuration options for private keys
diff --git a/internal/apis/certmanager/v1beta1/zz_generated.conversion.go b/internal/apis/certmanager/v1beta1/zz_generated.conversion.go
index 72b72178e..6aa9b3537 100644
--- a/internal/apis/certmanager/v1beta1/zz_generated.conversion.go
+++ b/internal/apis/certmanager/v1beta1/zz_generated.conversion.go
@@ -843,6 +843,7 @@ func autoConvert_v1beta1_CertificateSpec_To_certmanager_CertificateSpec(in *Cert
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]certmanager.CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
@@ -881,6 +882,7 @@ func autoConvert_certmanager_CertificateSpec_To_v1beta1_CertificateSpec(in *cert
 	out.EncodeUsagesInRequest = (*bool)(unsafe.Pointer(in.EncodeUsagesInRequest))
 	out.RevisionHistoryLimit = (*int32)(unsafe.Pointer(in.RevisionHistoryLimit))
 	out.AdditionalOutputFormats = *(*[]CertificateAdditionalOutputFormat)(unsafe.Pointer(&in.AdditionalOutputFormats))
+	out.CertificateOwnerRef = (*bool)(unsafe.Pointer(in.CertificateOwnerRef))
 	return nil
 }
 
diff --git a/internal/apis/certmanager/v1beta1/zz_generated.deepcopy.go b/internal/apis/certmanager/v1beta1/zz_generated.deepcopy.go
index 7644138e1..fee02661c 100644
--- a/internal/apis/certmanager/v1beta1/zz_generated.deepcopy.go
+++ b/internal/apis/certmanager/v1beta1/zz_generated.deepcopy.go
@@ -467,6 +467,11 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
 		*out = make([]CertificateAdditionalOutputFormat, len(*in))
 		copy(*out, *in)
 	}
+	if in.CertificateOwnerRef != nil {
+		in, out := &in.CertificateOwnerRef, &out.CertificateOwnerRef
+		*out = new(bool)
+		**out = **in
+	}
 	return
 }
 
diff --git a/internal/apis/certmanager/zz_generated.deepcopy.go b/internal/apis/certmanager/zz_generated.deepcopy.go
index 67361a89e..dac61e476 100644
--- a/internal/apis/certmanager/zz_generated.deepcopy.go
+++ b/internal/apis/certmanager/zz_generated.deepcopy.go
@@ -467,6 +467,12 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
 		*out = make([]CertificateAdditionalOutputFormat, len(*in))
 		copy(*out, *in)
 	}
+
+	if in.CertificateOwnerRef != nil {
+		in, out := &in.CertificateOwnerRef, &out.CertificateOwnerRef
+		*out = new(bool)
+		**out = **in
+	}
 	return
 }
 
diff --git a/pkg/apis/certmanager/v1/types_certificate.go b/pkg/apis/certmanager/v1/types_certificate.go
index 767a18ffc..7e6a648ff 100644
--- a/pkg/apis/certmanager/v1/types_certificate.go
+++ b/pkg/apis/certmanager/v1/types_certificate.go
@@ -202,6 +202,12 @@ type CertificateSpec struct {
 	// the controller and webhook components.
 	// +optional
 	AdditionalOutputFormats []CertificateAdditionalOutputFormat `json:"additionalOutputFormats,omitempty"`
+
+	// CertificateOwnerRef is whether to set the certificate resource as an owner of secret where the tls certificate is stored.
+	// When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted.
+	// If unset (`nil`) `--enable-certificate-owner-ref` CLI parameter value is used. Default value is `nil`.
+	// +optional
+	CertificateOwnerRef *bool `json:"certificateOwnerRef,omitempty"`
 }
 
 // CertificatePrivateKey contains configuration options for private keys
diff --git a/pkg/apis/certmanager/v1/zz_generated.deepcopy.go b/pkg/apis/certmanager/v1/zz_generated.deepcopy.go
index 8ba5ea3aa..fdbb35c07 100644
--- a/pkg/apis/certmanager/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/certmanager/v1/zz_generated.deepcopy.go
@@ -467,6 +467,11 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
 		*out = make([]CertificateAdditionalOutputFormat, len(*in))
 		copy(*out, *in)
 	}
+	if in.CertificateOwnerRef != nil {
+		in, out := &in.CertificateOwnerRef, &out.CertificateOwnerRef
+		*out = new(bool)
+		**out = **in
+	}
 	return
 }
 
diff --git a/pkg/controller/certificates/issuing/internal/secret.go b/pkg/controller/certificates/issuing/internal/secret.go
index ad952e031..fda4276d7 100644
--- a/pkg/controller/certificates/issuing/internal/secret.go
+++ b/pkg/controller/certificates/issuing/internal/secret.go
@@ -102,10 +102,16 @@ func (s *SecretsManager) UpdateData(ctx context.Context, crt *cmapi.Certificate,
 		WithAnnotations(secret.Annotations).WithLabels(secret.Labels).
 		WithData(secret.Data).WithType(secret.Type)
 
+	certificateOwnerRef := s.enableSecretOwnerReferences
+	// Check the CertificateOwnerRef field of the certificate, and if it is not nil, override enableSecretOwnerReferences with the CertificateOwnerRef value.
+	if crt.Spec.CertificateOwnerRef != nil {
+		certificateOwnerRef = *crt.Spec.CertificateOwnerRef
+	}
+
 	// If Secret owner reference is enabled, set it on the Secret. This results
 	// in a no-op if the Secret already exists and has the owner reference set,
 	// and visa-versa.
-	if s.enableSecretOwnerReferences {
+	if certificateOwnerRef {
 		ref := *metav1.NewControllerRef(crt, certificateGvk)
 		applyCnf = applyCnf.WithOwnerReferences(&applymetav1.OwnerReferenceApplyConfiguration{
 			APIVersion: &ref.APIVersion, Kind: &ref.Kind,
diff --git a/pkg/controller/certificates/issuing/internal/secret_test.go b/pkg/controller/certificates/issuing/internal/secret_test.go
index 49a9db3d2..0889a7e7a 100644
--- a/pkg/controller/certificates/issuing/internal/secret_test.go
+++ b/pkg/controller/certificates/issuing/internal/secret_test.go
@@ -72,6 +72,30 @@ func Test_SecretsManager(t *testing.T) {
 		gen.SetCertificateDNSNames("example.com"),
 	), fixedClock)
 
+	baseCertWithCertificateOwnerRefEnabled := gen.Certificate("test",
+		gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: "ca-issuer", Kind: "Issuer", Group: "foo.io"}),
+		gen.SetCertificateSecretName("output"),
+		gen.SetCertificateRenewBefore(time.Hour*36),
+		gen.SetCertificateDNSNames("example.com"),
+		gen.SetCertificateUID(apitypes.UID("test-uid")),
+		gen.SetCertificateOwnerRef(true),
+	)
+	baseCertBundleWithCertificateOwnerRefEnabled := testcrypto.MustCreateCryptoBundle(t, gen.CertificateFrom(baseCertWithCertificateOwnerRefEnabled,
+		gen.SetCertificateDNSNames("example.com"),
+	), fixedClock)
+
+	baseCertWithCertificateOwnerRefDisabled := gen.Certificate("test",
+		gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: "ca-issuer", Kind: "Issuer", Group: "foo.io"}),
+		gen.SetCertificateSecretName("output"),
+		gen.SetCertificateRenewBefore(time.Hour*36),
+		gen.SetCertificateDNSNames("example.com"),
+		gen.SetCertificateUID(apitypes.UID("test-uid")),
+		gen.SetCertificateOwnerRef(false),
+	)
+	baseCertBundleWithCertificateOwnerRefDisabled := testcrypto.MustCreateCryptoBundle(t, gen.CertificateFrom(baseCertWithCertificateOwnerRefDisabled,
+		gen.SetCertificateDNSNames("example.com"),
+	), fixedClock)
+
 	baseCertWithSecretTemplate := gen.CertificateFrom(baseCertBundle.Certificate,
 		gen.SetCertificateSecretTemplate(map[string]string{
 			"template":  "annotation",
@@ -155,6 +179,77 @@ func Test_SecretsManager(t *testing.T) {
 			expectedErr: false,
 		},
 
+		"if secret does not exist, but certificateOwnerRef is set to true, create new Secret, with owner disabled": {
+			certificateOptions: controllerpkg.CertificateOptions{EnableOwnerRef: false},
+			certificate:        baseCertBundleWithCertificateOwnerRefEnabled.Certificate,
+			existingSecret:     nil,
+			secretData:         SecretData{Certificate: baseCertBundle.CertBytes, CA: []byte("test-ca"), PrivateKey: []byte("test-key")},
+			applyFn: func(t *testing.T) testcoreclients.ApplyFn {
+				return func(_ context.Context, gotCnf *applycorev1.SecretApplyConfiguration, gotOpts metav1.ApplyOptions) (*corev1.Secret, error) {
+					expUID := apitypes.UID("test-uid")
+					expCnf := applycorev1.Secret("output", gen.DefaultTestNamespace).
+						WithAnnotations(
+							map[string]string{
+								cmapi.CertificateNameKey: "test", cmapi.IssuerGroupAnnotationKey: "foo.io",
+								cmapi.IssuerKindAnnotationKey: "Issuer", cmapi.IssuerNameAnnotationKey: "ca-issuer",
+
+								cmapi.CommonNameAnnotationKey: baseCertBundle.Cert.Subject.CommonName, cmapi.AltNamesAnnotationKey: strings.Join(baseCertBundle.Cert.DNSNames, ","),
+								cmapi.IPSANAnnotationKey:  strings.Join(utilpki.IPAddressesToString(baseCertBundle.Cert.IPAddresses), ","),
+								cmapi.URISANAnnotationKey: strings.Join(utilpki.URLsToString(baseCertBundle.Cert.URIs), ","),
+							}).
+						WithLabels(make(map[string]string)).
+						WithData(map[string][]byte{
+							corev1.TLSCertKey:       baseCertBundle.CertBytes,
+							corev1.TLSPrivateKeyKey: []byte("test-key"),
+							cmmeta.TLSCAKey:         []byte("test-ca"),
+						}).
+						WithType(corev1.SecretTypeTLS).
+						WithOwnerReferences(&applymetav1.OwnerReferenceApplyConfiguration{
+							APIVersion: pointer.String("cert-manager.io/v1"), Kind: pointer.String("Certificate"),
+							Name: pointer.String("test"), UID: &expUID,
+							Controller: pointer.Bool(true), BlockOwnerDeletion: pointer.Bool(true),
+						})
+
+					assert.Equal(t, expCnf, gotCnf)
+
+					expOpts := metav1.ApplyOptions{FieldManager: "cert-manager-test"}
+					assert.Equal(t, expOpts, gotOpts)
+
+					return nil, nil
+				}
+			},
+			expectedErr: false,
+		},
+
+		"if secret does not exist, but certificateOwnerRef is set to false, create new Secret, with owner enabled": {
+			certificateOptions: controllerpkg.CertificateOptions{EnableOwnerRef: true},
+			certificate:        baseCertBundleWithCertificateOwnerRefDisabled.Certificate,
+			existingSecret:     nil,
+			secretData:         SecretData{Certificate: baseCertBundle.CertBytes, CA: []byte("test-ca"), PrivateKey: []byte("test-key")},
+			applyFn: func(t *testing.T) testcoreclients.ApplyFn {
+				return func(_ context.Context, gotCnf *applycorev1.SecretApplyConfiguration, gotOpts metav1.ApplyOptions) (*corev1.Secret, error) {
+					expCnf := applycorev1.Secret("output", gen.DefaultTestNamespace).
+						WithAnnotations(
+							map[string]string{
+								cmapi.CertificateNameKey: "test", cmapi.IssuerGroupAnnotationKey: "foo.io", cmapi.IssuerKindAnnotationKey: "Issuer",
+								cmapi.IssuerNameAnnotationKey: "ca-issuer", cmapi.CommonNameAnnotationKey: baseCertBundle.Cert.Subject.CommonName,
+								cmapi.AltNamesAnnotationKey: strings.Join(baseCertBundle.Cert.DNSNames, ","), cmapi.IPSANAnnotationKey: strings.Join(utilpki.IPAddressesToString(baseCertBundle.Cert.IPAddresses), ","),
+								cmapi.URISANAnnotationKey: strings.Join(utilpki.URLsToString(baseCertBundle.Cert.URIs), ","),
+							}).
+						WithLabels(make(map[string]string)).
+						WithData(map[string][]byte{corev1.TLSCertKey: baseCertBundle.CertBytes, corev1.TLSPrivateKeyKey: []byte("test-key"), cmmeta.TLSCAKey: []byte("test-ca")}).
+						WithType(corev1.SecretTypeTLS)
+					assert.Equal(t, expCnf, gotCnf)
+
+					expOpts := metav1.ApplyOptions{FieldManager: "cert-manager-test"}
+					assert.Equal(t, expOpts, gotOpts)
+
+					return nil, nil
+				}
+			},
+			expectedErr: false,
+		},
+
 		"if secret does not exist, create new Secret, with owner enabled": {
 			certificateOptions: controllerpkg.CertificateOptions{EnableOwnerRef: true},
 			certificate:        baseCertBundle.Certificate,
@@ -235,6 +330,7 @@ func Test_SecretsManager(t *testing.T) {
 			},
 			expectedErr: false,
 		},
+
 		"if secret does exist, update existing Secret and leave custom annotations and labels, with owner enabled": {
 			certificateOptions: controllerpkg.CertificateOptions{EnableOwnerRef: true},
 			certificate:        baseCertBundle.Certificate,
@@ -277,6 +373,103 @@ func Test_SecretsManager(t *testing.T) {
 						})
 					assert.Equal(t, expCnf, gotCnf)
 
+					expOpts := metav1.ApplyOptions{FieldManager: "cert-manager-test"}
+					assert.Equal(t, expOpts, gotOpts)
+
+					return nil, nil
+				}
+			},
+			expectedErr: false,
+		},
+
+		"if secret does exist, but certificateOwnerRef is set to true, update existing Secret and leave custom annotations, with owner disabled": {
+			certificateOptions: controllerpkg.CertificateOptions{EnableOwnerRef: false},
+			certificate:        baseCertBundleWithCertificateOwnerRefEnabled.Certificate,
+			existingSecret: &corev1.Secret{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace:   gen.DefaultTestNamespace,
+					Name:        "output",
+					Annotations: map[string]string{"my-custom": "annotation"},
+					Labels:      map[string]string{},
+				},
+				Data: map[string][]byte{corev1.TLSCertKey: []byte("foo"), corev1.TLSPrivateKeyKey: []byte("foo"), cmmeta.TLSCAKey: []byte("foo")},
+				Type: corev1.SecretTypeTLS,
+			},
+			secretData: SecretData{Certificate: baseCertBundle.CertBytes, CA: []byte("test-ca"), PrivateKey: []byte("test-key")},
+			applyFn: func(t *testing.T) testcoreclients.ApplyFn {
+				return func(_ context.Context, gotCnf *applycorev1.SecretApplyConfiguration, gotOpts metav1.ApplyOptions) (*corev1.Secret, error) {
+					expUID := apitypes.UID("test-uid")
+					expCnf := applycorev1.Secret("output", gen.DefaultTestNamespace).
+						WithAnnotations(
+							map[string]string{
+								cmapi.CertificateNameKey: "test", cmapi.IssuerGroupAnnotationKey: "foo.io",
+								cmapi.IssuerKindAnnotationKey: "Issuer", cmapi.IssuerNameAnnotationKey: "ca-issuer",
+
+								cmapi.CommonNameAnnotationKey: baseCertBundle.Cert.Subject.CommonName,
+								cmapi.AltNamesAnnotationKey:   strings.Join(baseCertBundle.Cert.DNSNames, ","),
+								cmapi.IPSANAnnotationKey:      strings.Join(utilpki.IPAddressesToString(baseCertBundle.Cert.IPAddresses), ","),
+								cmapi.URISANAnnotationKey:     strings.Join(utilpki.URLsToString(baseCertBundle.Cert.URIs), ","),
+							}).
+						WithLabels(make(map[string]string)).
+						WithData(map[string][]byte{
+							corev1.TLSCertKey:       baseCertBundle.CertBytes,
+							corev1.TLSPrivateKeyKey: []byte("test-key"),
+							cmmeta.TLSCAKey:         []byte("test-ca"),
+						}).
+						WithType(corev1.SecretTypeTLS).
+						WithOwnerReferences(&applymetav1.OwnerReferenceApplyConfiguration{
+							APIVersion: pointer.String("cert-manager.io/v1"), Kind: pointer.String("Certificate"),
+							Name: pointer.String("test"), UID: &expUID,
+							Controller: pointer.Bool(true), BlockOwnerDeletion: pointer.Bool(true),
+						})
+
+					assert.Equal(t, expCnf, gotCnf)
+
+					expOpts := metav1.ApplyOptions{FieldManager: "cert-manager-test"}
+					assert.Equal(t, expOpts, gotOpts)
+
+					return nil, nil
+				}
+			},
+			expectedErr: false,
+		},
+
+		"if secret does exist, but certificateOwnerRef is set to false ,update existing Secret and leave custom annotations, with owner enabled": {
+			certificateOptions: controllerpkg.CertificateOptions{EnableOwnerRef: true},
+			certificate:        baseCertBundleWithCertificateOwnerRefDisabled.Certificate,
+			existingSecret: &corev1.Secret{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace:   gen.DefaultTestNamespace,
+					Name:        "output",
+					Annotations: map[string]string{"my-custom": "annotation"},
+					Labels:      map[string]string{},
+				},
+				Data: map[string][]byte{corev1.TLSCertKey: []byte("foo"), corev1.TLSPrivateKeyKey: []byte("foo"), cmmeta.TLSCAKey: []byte("foo")},
+				Type: corev1.SecretTypeTLS,
+			},
+			secretData: SecretData{Certificate: baseCertBundle.CertBytes, CA: []byte("test-ca"), PrivateKey: []byte("test-key")},
+			applyFn: func(t *testing.T) testcoreclients.ApplyFn {
+				return func(_ context.Context, gotCnf *applycorev1.SecretApplyConfiguration, gotOpts metav1.ApplyOptions) (*corev1.Secret, error) {
+					expCnf := applycorev1.Secret("output", gen.DefaultTestNamespace).
+						WithAnnotations(
+							map[string]string{
+								cmapi.CertificateNameKey: "test", cmapi.IssuerGroupAnnotationKey: "foo.io",
+								cmapi.IssuerKindAnnotationKey: "Issuer", cmapi.IssuerNameAnnotationKey: "ca-issuer",
+
+								cmapi.CommonNameAnnotationKey: baseCertBundle.Cert.Subject.CommonName,
+								cmapi.AltNamesAnnotationKey:   strings.Join(baseCertBundle.Cert.DNSNames, ","),
+								cmapi.IPSANAnnotationKey:      strings.Join(utilpki.IPAddressesToString(baseCertBundle.Cert.IPAddresses), ","),
+								cmapi.URISANAnnotationKey:     strings.Join(utilpki.URLsToString(baseCertBundle.Cert.URIs), ","),
+							}).
+						WithLabels(make(map[string]string)).
+						WithData(map[string][]byte{
+							corev1.TLSCertKey:       baseCertBundle.CertBytes,
+							corev1.TLSPrivateKeyKey: []byte("test-key"),
+							cmmeta.TLSCAKey:         []byte("test-ca"),
+						}).
+						WithType(corev1.SecretTypeTLS)
+					assert.Equal(t, expCnf, gotCnf)
+
 					expOpts := metav1.ApplyOptions{FieldManager: "cert-manager-test", Force: true}
 					assert.Equal(t, expOpts, gotOpts)
 
diff --git a/test/unit/gen/certificate.go b/test/unit/gen/certificate.go
index 22766e228..aa02588b2 100644
--- a/test/unit/gen/certificate.go
+++ b/test/unit/gen/certificate.go
@@ -278,3 +278,9 @@ func SetCertificateAdditionalOutputFormats(additionalOutputFormats ...v1.Certifi
 		crt.Spec.AdditionalOutputFormats = additionalOutputFormats
 	}
 }
+
+func SetCertificateOwnerRef(ownerRef bool) CertificateModifier {
+	return func(crt *v1.Certificate) {
+		crt.Spec.CertificateOwnerRef = &ownerRef
+	}
+}
